﻿/**	archive_file_filter.hpp
 *	----	Create Time Stamp	--2009-01-25 14:04:49--
 *------------------------------------------------------------------------------
 *	Mean	:
 *	Author	:Nick Shallery	(nicknide@gmail.com)
 *	Version	:1.0.4.8	(2009-08-16 23:37:56)
 *------------------------------------------------------------------------------
**/	/*YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.*/

#if			!defined(__LOLIX_TOY__ARCHIVE_FILE_FILTER__NICK__K_IN_G__)
#define		__LOLIX_TOY__ARCHIVE_FILE_FILTER__NICK__K_IN_G__
//==============================================================================
//--------------------------------------------------------------------------
#if			!defined(__LOLIX__LOLI__FILE__K_IN_G__)
	#include	"../loli/file.h"
#endif	//	!defined(__LOLIX__LOLI__FILE__K_IN_G__)
//--------------------------------------------------------------------------
//==============================================================================
#endif	//	!defined(__LOLIX_TOY__ARCHIVE_FILE_FILTER__NICK__K_IN_G__)


#if			defined(LOLIX_DEF__MEMORY_FILE_STREAM) && !defined(__LOLIX__ALREADY_DEFINE_MEMORY_FILE_STRAEM__)
#define		__LOLIX__ALREADY_DEFINE_MEMORY_FILE_STRAEM__
	#if			!defined(__LOLIX__TOY__STDC_FUN__NICK__K_IN_G__)
		#include	"./stdc_fun.h"
	#endif	//	!defined(__LOLIX__TOY__STDC_FUN__NICK__K_IN_G__)
	#if			!defined(__LOLIX__TOY__STD_VECTOR__NICK__K_IN_G__)
		#include	"./std_vector.hpp"
	#endif	//	!defined(__LOLIX__TOY__STD_VECTOR__NICK__K_IN_G__)

namespace	lolix{namespace loli{
	template<typename _TAlc>
	class	memory_file_stream;
}}


template<typename _TAlc>
class	lolix::loli::memory_file_stream
	: public file_stream
{
	CANNT_COPY_LOLI;
	typedef	toy::vector<lx_u8, _TAlc>	data_type;
	data_type	_dat;
	size_type	_cur;
	toy::stdc_fun*	_stdc;
	void* operator new(size_t);
	void operator delete(void*);
public:
	//LOLIX_DEFINE_ITF_ID(0x6f0fdcab, 0x44694ef7, 0x9bd120e2, 0x06baf42a);

	LOLIX_INLINE_CALL	memory_file_stream<_TAlc>(toy::stdc_fun* stdc): _cur(0), _stdc(stdc){_stdc->inc_ref();}
	explicit LOLIX_INLINE_CALL	memory_file_stream<_TAlc>(toy::stdc_fun* stdc, _TAlc alc) : _cur(0), _stdc(stdc), _dat(alc){_stdc->inc_ref();}
	explicit LOLIX_INLINE_CALL	memory_file_stream<_TAlc>(data_type& dat, toy::stdc_fun* stdc) : _cur(0), _dat(dat){_stdc->inc_ref();}
	~memory_file_stream<_TAlc>(void){if ( _stdc ) _stdc->release();}

	LOLIX_INTERFACE_DEFINE(inc_ref		, size_type		, (void)const)
	{
		return 2;
	}
	LOLIX_INTERFACE_DEFINE(release		, size_type		, (void)const)
	{
		return 0;
	}
	LOLIX_INTERFACE_DEFINE(itf_id		, void			, (LOLIX_ITF_ID* outid)const)
	{
		LOLIX_ASSERT(0, "UNSUPPORT INTERFACE");
	}
	LOLIX_INTERFACE_DEFINE(query_itf	, LOLIX_RETNV	, (itf** out_ptr, const LOLIX_ITF_ID* in_id))
	{
		if ( !LOLIX_ITF_ID_EQUL_WITH_TYPE(in_id, file_stream) )
			return LOLIX_ERROR_INVALID_TYPE;

		*out_ptr = this;
		return LOLIX_RETNV_OK;
	}
	LOLIX_INTERFACE_DEFINE(size			, lx_u64		, (void)const)
	{
		return _dat.size();
	}

	LOLIX_INTERFACE_DEFINE(close		, LOLIX_RETNV	, (void))
	{
		_stdc->release();
		_stdc = 0;
		return LOLIX_RETNV_OK;
	}

	LOLIX_INTERFACE_DEFINE(opt_flag		, void	, (open_flag* const of)const)
	{
		of->flag = 0;
		of->operat_read = 1;
		of->operat_write = 1;
		of->type_mask = of->create_new;
		of->with_flow = 1;
		of->with_bidir = 1;
	}

	LOLIX_INTERFACE_DEFINE(get_name	, LOLIX_RETNV	, (LOLIX_ITF_ID* const out_id, wchar_t full_name[], size_type* const io_file_name_len)const)
	{
		return LOLIX_ERROR_UNSUPPORT_INTERFACE;
	}
	LOLIX_INTERFACE_DEFINE(remove		, LOLIX_RETNV	, (void))
	{
		return LOLIX_ERROR_UNSUPPORT_INTERFACE;
	}
	//	out_ptr can be null, but it maybe lost during some times.
	LOLIX_INTERFACE_DEFINE(reopen		, LOLIX_RETNV	, (file** out_ptr, size_type opt_flag, void* reserve))
	{
		return LOLIX_ERROR_UNSUPPORT_INTERFACE;
	}
	//	new_offset: [in] need offset, [out] new offset >> distance of begining
	//	int : 0 -> from header, 1 -> from current, 2 -> from end
	LOLIX_INTERFACE_DEFINE(seek	, LOLIX_RETNV	, (lx_i64* new_offset, int start))
	{
		if ( *new_offset > 0 && *new_offset > lolix::type::type_value<REBIND_TYPE(_cur)>::max_val
			|| *new_offset < 0 && -*new_offset < lolix::type::type_value<REBIND_TYPE(_cur)>::max_val )
				return LOLIX_ERROR_OUT_OF_RANGE;

		LOLIX_ASSERT(start < 2 || *new_offset <= 0, L"offset must less or equal than zero");

		switch ( start )
		{
		case 0:
			_cur = (size_type)*new_offset;
			break;

		case 1:
			if ( *new_offset > 0 && lolix::type::type_value<REBIND_TYPE(_cur)>::max_val - _cur < (size_type)*new_offset
				|| *new_offset < 0 && _cur < ((size_type)-*new_offset) )
				return LOLIX_ERROR_OUT_OF_RANGE;

			_cur += (size_type)*new_offset;
			*new_offset = _cur;
			break;

		case 2:
			if ( static_cast<lolix::size_type>(-*new_offset) > _dat.size() )
				return LOLIX_ERROR_OUT_OF_RANGE;

			*new_offset = _dat.size() + *new_offset;
			break;

		default:
			return LOLIX_ERROR_INVALID_PARAM;
		}

		if ( _cur > _dat.size() )
			_dat.resize(_cur);

		return LOLIX_RETNV_OK;
	}

	LOLIX_INTERFACE_DEFINE(touch, LOLIX_RETNV	, (void* buf, size_type* buf_size, sync_call_back* call_back))
	{
		LOLIX_ASSERT(!call_back, L"Unsupport param input");
		if ( !_stdc )
			return LOLIX_ERROR_INVALID_STATE;

		if ( _cur == _dat.size() )
		{
			*buf_size = 0;
			return LOLIX_RETNV_OK;
		}

		const size_type less_size = _dat.size() - _cur;
		const size_type cp_size = (*buf_size < less_size)?*buf_size:less_size;
		_stdc->memcpy(buf, &*_dat.begin() + _cur, cp_size);
		*buf_size = cp_size;
		return LOLIX_RETNV_OK;
	}

	LOLIX_INTERFACE_DEFINE(read	, LOLIX_RETNV	, (void* buf, size_type* buf_size, sync_call_back* call_back))
	{
		LOLIX_RETNV rtv;
		if ( LOLIX_IS_ERROR(rtv = touch(buf, buf_size, call_back)) )
			return rtv;
		_cur += *buf_size;
		return LOLIX_RETNV_OK;
	}
	LOLIX_INTERFACE_DEFINE(write, LOLIX_RETNV	, (const void* buf	, size_type* buf_size, sync_call_back* call_back))
	{
		LOLIX_ASSERT(!call_back, L"Unsupport param input");
		if ( !_stdc )
			return LOLIX_ERROR_INVALID_STATE;

		const size_type total_size = _cur + *buf_size;
		if ( total_size < _cur )
			return LOLIX_ERROR_OUT_OF_RANGE;

		if ( _dat.size() < total_size )
			_dat.resize(total_size);

		_stdc->memcpy(&*_dat.begin() + _cur, buf, *buf_size);
		_cur += *buf_size;
		return LOLIX_RETNV_OK;
	}
};


#endif	//	defined(LOLIX_DEF__MEMORY_FILE_STREAM) && !defined(__LOLIX__ALREADY_DEFINE_MEMORY_FILE_STRAEM__)

